package com.itrident.action;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.PsiClassImpl;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiTypesUtil;
import com.intellij.psi.util.PsiUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;

import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

public class CopyAsJSONAction extends AnAction {

    @NonNls
    private static final Map<String, Object> PROPERTIES_TYPES = new HashMap<> (16);

    static {
        // 包装数据类型
        PROPERTIES_TYPES.put("Byte", 0);
        PROPERTIES_TYPES.put("Short", 0);
        PROPERTIES_TYPES.put("Integer", 0);
        PROPERTIES_TYPES.put("Long", 0L);
        PROPERTIES_TYPES.put("Float", 0.0F);
        PROPERTIES_TYPES.put("Double", 0.0D);
        PROPERTIES_TYPES.put("Boolean", false);
        // 其他
        PROPERTIES_TYPES.put("String", "");
        PROPERTIES_TYPES.put("BigDecimal", BigDecimal.ZERO);
        PROPERTIES_TYPES.put("Date", null);
        PROPERTIES_TYPES.put("LocalDate", null);
        PROPERTIES_TYPES.put("LocalTime", null);
        PROPERTIES_TYPES.put("LocalDateTime", null);
    }

    @Override
    public void update(@NotNull AnActionEvent e) {
        PsiElement psiElement = e.getData (CommonDataKeys.PSI_ELEMENT);
        e.getPresentation ().setEnabled (psiElement instanceof PsiClassImpl);
    }

    @Override
    public void actionPerformed(AnActionEvent e) {
        PsiElement psiElement = e.getData (CommonDataKeys.PSI_ELEMENT);
        PsiClassImpl psiClass = (PsiClassImpl) psiElement;
        Map<String, Object> fieldsMap = getFields (psiClass);
        Gson gson = new GsonBuilder ().serializeNulls().create();
        String json = gson.toJson (fieldsMap);
        Clipboard systemClipboard = Toolkit.getDefaultToolkit ().getSystemClipboard ();
        StringSelection transferable = new StringSelection (json);
        systemClipboard.setContents (transferable,transferable);
    }

    public static Map<String, Object> getFields(PsiClass psiClass) {
        Map<String, Object> fieldMap = new LinkedHashMap<> ();
        if (psiClass != null && !psiClass.isEnum() && !psiClass.isInterface() && !psiClass.isAnnotationType()) {
            for (PsiField field : psiClass.getAllFields()) {
                PsiType type = field.getType();
                String name = field.getName();
               if (type instanceof PsiPrimitiveType) {
                    // 基本类型
                    fieldMap.put(name, PsiTypesUtil.getDefaultValue(type));
                } else {
                    //reference Type
                    String fieldTypeName = type.getPresentableText();
                    if (PROPERTIES_TYPES.containsKey(fieldTypeName)) {
                        fieldMap.put(name, PROPERTIES_TYPES.get(fieldTypeName));
                    } else if (type instanceof PsiArrayType) {
                        //array type
                        java.util.List<Object> list = new ArrayList<> ();
                        PsiType deepType = type.getDeepComponentType();
                        String deepTypeName = deepType.getPresentableText();
                        if (deepType instanceof PsiPrimitiveType) {
                            list.add(PsiTypesUtil.getDefaultValue(deepType));
                        } else if (PROPERTIES_TYPES.containsKey(deepTypeName)) {
                            list.add(PROPERTIES_TYPES.get(deepTypeName));
                        } else {
                            list.add(getFields(PsiUtil.resolveClassInType(deepType)));
                        }
                        fieldMap.put(name, list);
                    } else if (InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_UTIL_COLLECTION)) {
                        // List Set or HashSet
                        java.util.List<Object> list = new ArrayList<>();
                        PsiType iterableType = PsiUtil.extractIterableTypeParameter(type, false);
                        PsiClass iterableClass = PsiUtil.resolveClassInClassTypeOnly(iterableType);
                        if (iterableClass != null) {
                            String classTypeName = iterableClass.getName();
                            if (PROPERTIES_TYPES.containsKey(classTypeName)) {
                                list.add(PROPERTIES_TYPES.get(classTypeName));
                            } else {
                                list.add(getFields(iterableClass));
                            }
                        }
                        fieldMap.put(name, list);
                    } else if (InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_UTIL_MAP)) {
                        // HashMap or Map
                        fieldMap.put(name, new HashMap<>(4));
                    } else if (psiClass.isEnum() || psiClass.isInterface() || psiClass.isAnnotationType()) {
                        // enum or interface
                        fieldMap.put(name, "");
                    } else {
                        fieldMap.put(name, getFields(PsiUtil.resolveClassInType(type)));
                    }
                }
            }
        }
        return fieldMap;
    }



}
